/*

 * Copyright (C) 2021 Huawei Device Co., Ltd.

 * Licensed under the Apache License, Version 2.0 (the "License");

 * you may not use this file except in compliance with the License.

 * You may obtain a copy of the License at

 *

 *     http://www.apache.org/licenses/LICENSE-2.0

 *

 * Unless required by applicable law or agreed to in writing, software

 * distributed under the License is distributed on an "AS IS" BASIS,

 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

 * See the License for the specific language governing permissions and

 * limitations under the License.

 */
package org.aviran.cookiebar2;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Image;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.hiviewdfx.HiLog;
import ohos.hiviewdfx.HiLogLabel;
import ohos.multimodalinput.event.TouchEvent;


/**
 * CookieTopView
 *
 * @since : 2021.5.24
 */
public class CookieTopView extends ComponentContainer implements Component.TouchEventListener {
    private static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00201, "MY_TAG");
    private static final int EVENT_MESSAGE_TOP = 1;

    /**
     * 下拉栏是否存在
     */
    public Boolean isTopExist = false;
    /**
     * 是否需要Top栏上去了在下来
     */
    public Boolean isNeedTopToBottom = true;
    /**
     * 侧边栏是否存在
     */
    public Boolean isLeftExit = false;
    /**
     * 是否需要侧边栏出去了在弹出来
     */
    public Boolean isNeedLeftToRight = true;

    private Component myComponent;
    private ShapeElement element;
    private AnimatorValue mAnimator;
    private CookieBottomView cookieBottomView;
    private InnerEvent event;
    private MyEventHandler myHandler;
    private EventRunner runner;

    private Text title;
    private Text message;
    private Text action;
    private Image image;
    private Text displayText;
    private Color titleColor;
    private Color messageColor;
    private String titleStr;
    private String messageStr;
    private String actionStr;
    private Boolean isMoved = false; // 是否移动了的
    private Boolean isNeedBottomMove = false; // 下面是否需要移动
    private Boolean isTopNeedMove = false; // 上方是否需要移动
    private int dropX = 0;
    private int dropY = 0;
    private int moveX = 0;
    private int duration = 5000;
    private Integer iconID;


    /**
     * CookieTopView构造器
     *
     * @param context context
     * @param attrSet 属性
     */
    public CookieTopView(final Context context, final AttrSet attrSet) {
        super(context, attrSet);
        myComponent = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_cookie_top_layout, null, false);
        if (myComponent.findComponentById(ResourceTable.Id_title) instanceof Text) {
            title = (Text) myComponent.findComponentById(ResourceTable.Id_title);
        }
        if (myComponent.findComponentById(ResourceTable.Id_message) instanceof Text) {
            message = (Text) myComponent.findComponentById(ResourceTable.Id_message);
        }
        if (myComponent.findComponentById(ResourceTable.Id_action) instanceof Text) {
            action = (Text) myComponent.findComponentById(ResourceTable.Id_action);
        }
        if (myComponent.findComponentById(ResourceTable.Id_img) instanceof Image) {
            image = (Image) myComponent.findComponentById(ResourceTable.Id_img);
        }
        myComponent.setVisibility(Component.HIDE);
        myComponent.setClickedListener(component -> {
            // 设置一个监听事件，避免点击穿透触发component下面的button点击事件
        });
        titleStr = getString(attrSet, "title", "");
        messageStr = getString(attrSet, "message", "");
        setTouchEventListener(this);
        addComponent(myComponent);
        mAnimator = new AnimatorValue();
    }

    /**
     * set Display Text
     *
     * @param displayText 文字显示
     */
    public void setDisplayText(Text displayText) {
        this.displayText = displayText;
    }

    /**
     * set Title
     *
     * @param titleStr 标题信息
     */
    public void setTitle(String titleStr) {
        this.titleStr = titleStr;
    }

    /**
     * set Title Color
     *
     * @param color 标题颜色
     */
    public void setTitleColor(Color color) {
        this.titleColor = color;
    }

    /**
     * set Message
     *
     * @param messageStr message信息
     */
    public void setMessage(String messageStr) {
        this.messageStr = messageStr;
    }

    /**
     * set Message Color
     *
     * @param color message颜色
     */
    public void setMessageColor(Color color) {
        this.messageColor = color;
    }

    /**
     * set Icon
     *
     * @param iconID 图标
     */
    public void setIcon(Integer iconID) {
        this.iconID = iconID;
    }

    /**
     * set Duration
     *
     * @param duration 动画持续时间
     */
    public void setDuration(Integer duration) {
        this.duration = duration;
    }

    /**
     * set actionStr
     *
     * @param actionStr action信息
     */
    public void setAction(String actionStr) {
        this.actionStr = actionStr;
    }

    /**
     * set Cookie Bottom View
     *
     * @param cookieBottomView cookieBottomView
     */
    public void setCookieBottomView(CookieBottomView cookieBottomView) {
        this.cookieBottomView = cookieBottomView;
    }

    /**
     * setBackgroundColor
     *
     * @param element 背景颜色
     */
    public void setBackgroundColor(ShapeElement element) {
        this.element = element;
    }

    private void setStyle() {
        title.setText(titleStr);
        message.setText(messageStr);
        myComponent.setBackground(element);
        action.setVisibility(Component.HIDE);
        if (iconID != null) {
            image.setPixelMap(iconID);
        }
        if (actionStr != null) {
            action.setText(actionStr);
            action.setVisibility(Component.VISIBLE);
        }
        if (titleColor != null) {
            title.setTextColor(titleColor);
        }
        if (messageColor != null) {
            message.setTextColor(messageColor);
        }
    }

    /**
     * start Top Animation
     */
    public void startAnimationTop() {
        myComponent.setTranslation(0, -325);
        AnimatorProperty animatorProperty = myComponent.createAnimatorProperty()
                .moveFromY(-325)
                .moveToY(0)
                .alpha(1f)
                .setDuration(500)
                .setCurveType(Animator.CurveType.OVERSHOOT);
        animatorProperty.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                myComponent.setVisibility(Component.VISIBLE);
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                isTopExist = true;
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        animatorProperty.start();
    }

    /**
     * start Bottom Animation
     */
    public void startAnimationBottom() {
        myComponent.setTranslation(0, 0);
        mAnimator.setDuration(500);
        mAnimator.setCurveType(Animator.CurveType.ANTICIPATE);
        mAnimator.setValueUpdateListener((animatorValue, value) -> {
            myComponent.setTranslation(myComponent.getTranslationX(), -value * 800f);
            myComponent.setVisibility(Component.VISIBLE);
        });
        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (isNeedTopToBottom) {
                    setStyle();
                    startAnimationTop();
                    if (displayText != null) {
                        displayText.setText("Replaced by new cookie");
                    }
                }
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimator.start();
    }

    /**
     * start Animation Top And Left Exit
     */
    public void startAnimationTopAndLeftExit() {
        // 先将侧边栏收回后再弹出下拉栏
        myComponent.setTranslationY(0);
        mAnimator.setDuration(500);
        mAnimator.setCurveType(Animator.CurveType.LINEAR);
        mAnimator.setValueUpdateListener((animatorValue, value) -> {
            myComponent.setTranslation(value * 1080, myComponent.getTranslationY());
            myComponent.setAlpha(1f - value);
        });
        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                myComponent.setVisibility(Component.VISIBLE);
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                setStyle();
                startAnimationTop();
                isTopExist = true;
                isLeftExit = false;
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimator.start();
    }

    /**
     * start Animation Top To Bottom
     */
    public void startAnimationTopToBottom() {
        isNeedTopToBottom = true;
        if (isLeftExit) {
            startAnimationTopAndLeftExit();
        } else {
            if (isTopExist) {
                startAnimationBottom();
            } else {
                setStyle();
                startAnimationTop();
            }
        }
        sendHandler();
    }

    /**
     * start Animation Left To Right
     */
    public void startAnimationLeftToRight() {
        isNeedLeftToRight = true;
        if (isTopExist) {
            startAnimationLeftAndTopIsExits();
        } else {
            if (isLeftExit) {
                startAnimationRight();
            } else {
                setStyle();
                startAnimationLeft();
            }
        }
        myComponent.setFocusable(FOCUS_ENABLE);
        sendHandler();
    }

    /**
     * start Left Animation
     */
    public void startAnimationLeft() {
        myComponent.setVisibility(Component.HIDE);
        myComponent.setContentPosition(-1080, 0);
        mAnimator.setDuration(500);
        mAnimator.setCurveType(Animator.CurveType.LINEAR);
        mAnimator.setValueUpdateListener((animatorValue, value) -> {
            myComponent.setVisibility(Component.VISIBLE);
            myComponent.setTranslation((value - 1) * 800, myComponent.getTranslationY());
            myComponent.setAlpha(value);
        });
        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                isLeftExit = true;
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimator.start();
    }

    /**
     * start Right Animation
     */
    public void startAnimationRight() {
        myComponent.setTranslation(0, 0);
        mAnimator.setDuration(500);
        mAnimator.setCurveType(Animator.CurveType.LINEAR);
        mAnimator.setValueUpdateListener((animatorValue, value) -> {
            myComponent.setTranslation(value * 1080f, myComponent.getTranslationY());
            myComponent.setVisibility(Component.VISIBLE);
            myComponent.setAlpha(1f - value);
        });
        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (isNeedLeftToRight) {
                    startAnimationLeft();
                }
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimator.start();
    }

    private void startAnimationLeftAndTopIsExits() {
        mAnimator.setDuration(500);
        mAnimator.setCurveType(Animator.CurveType.ANTICIPATE);
        mAnimator.setValueUpdateListener((animatorValue, value) -> {
            myComponent.setTranslation(myComponent.getTranslationX(), -value * 800);
            myComponent.setVisibility(Component.VISIBLE);
        });

        mAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                setStyle();
                // 初始化位置
                myComponent.setVisibility(Component.HIDE);
                myComponent.setContentPosition(0, 0);
                // 开始侧边栏
                startAnimationLeft();
                isTopExist = false;
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        mAnimator.start();
    }

    private class MyEventHandler extends EventHandler {
        private MyEventHandler(EventRunner runner) {
            super(runner);
        }

        // 重写实现processEvent方法
        @Override
        public void processEvent(InnerEvent event) {
            super.processEvent(event);
            if (event == null) {
                return;
            }
            int eventId = event.eventId;
            switch (eventId) {
                case EVENT_MESSAGE_TOP:
                    Object object = event.object;
                    if (object instanceof EventRunner) {
                        // 将原先线程的EventRunner实例投递给新创建的线程
                        EventRunner runner2 = (EventRunner) object;
                        // 将原先线程的EventRunner实例与新创建的线程的EventHandler绑定
                        EventHandler myHandler2 = new EventHandler(runner2) {
                            @Override
                            public void processEvent(InnerEvent event) {
                                if (isTopExist) {
                                    isNeedTopToBottom = false;
                                    startAnimationBottom();
                                    isTopExist = false;
                                }
                                if (isLeftExit) {
                                    isNeedLeftToRight = false;
                                    startAnimationRight();
                                    isLeftExit = false;
                                }
                                if (displayText != null) {
                                    displayText.setText("Cookie display duration completed");
                                }
                            }
                        };
                        int eventId2 = 2;
                        long param2 = 0L;
                        Object object2 = null;
                        InnerEvent event2 = InnerEvent.get(eventId2, param2, object2);
                        myHandler2.sendEvent(event2); // 投递事件到原先的线程
                    }
                    break;
                default:
                    break;
            }
        }
    }

    private void sendHandler() {
        if (runner != null && myHandler != null) {
            myHandler.removeAllEvent(); // 取消掉上一次发送的事件
        } else {
            runner = EventRunner.create(true); // create()的参数是true时，则为托管模式
            myHandler = new MyEventHandler(runner);
        }
        long param = 0L;
        event = InnerEvent.get(EVENT_MESSAGE_TOP, param, EventRunner.current());
        myHandler.removeAllEvent();
        myHandler.sendEvent(event, duration);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        int touchEventAction = touchEvent.getAction();
        switch (touchEventAction) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                // 首先判断落点是否在view的区域内，如果在，就可以移动，反之则不行
                isTopNeedMove = false; // 是否需要TopCookieBar移动
                isNeedBottomMove = false; // 是否需要BottomCookieBar移动
                isMoved = false; // 是否移动过
                dropX = (int) touchEvent.getPointerPosition(touchEvent.getIndex()).getX() - getLeft();
                dropY = (int) touchEvent.getPointerPosition(touchEvent.getIndex()).getY() - getTop();
                HiLog.info(LABEL, "isTopExist=" + isTopExist + "dropY" + dropY);
                cookieStatus();
                break;
            case TouchEvent.POINT_MOVE:
                moveX = (int) touchEvent.getPointerPosition(touchEvent.getIndex()).getX() - getLeft();
                // moveX - dropX 等于view的偏移量
                isMoved = true;
                isTopNeedMove();
                isNeedBottomMove();
                break;
            case TouchEvent.CANCEL:
            case TouchEvent.PRIMARY_POINT_UP:
                // 恢复原来的位置
                if (isMoved && isTopNeedMove) {
                    if (isLeftExit || isTopExist) {
                        startRestoreByUser((moveX - dropX), 0, (1 - (float) Math.abs(moveX - dropX) / 540));
                    }
                }
                if (isMoved && isNeedBottomMove) {
                    if (cookieBottomView.isExit) {
                        cookieBottomView.startRestoreByUser((moveX - dropX),
                                0, (1 - (float) Math.abs(moveX - dropX) / 540));
                    }
                }
                break;
            default:
        }
        return true;
    }

    private void cookieStatus() {
        if (isTopExist) {
            if (dropY < 325) {
                isTopNeedMove = true;
            }
        }
        if (isLeftExit) {
            if (dropY < 600) {
                isTopNeedMove = true;
            }
        }
        if (cookieBottomView != null) {
            if (cookieBottomView.isExit && cookieBottomView.bool == false) {
                if (dropY > (cookieBottomView.screenY - cookieBottomView.myHeight)) {
                    isNeedBottomMove = true;
                }
            }
        }
    }

    private void isTopNeedMove() {
        // 上方是否需要移动
        if (isTopNeedMove) {
            if (isLeftExit || isTopExist) {
                if (Math.abs(moveX - dropX) > 270) {
                    if (runner != null && myHandler != null) {
                        myHandler.removeAllEvent(); // 取消掉上一次发送的事件
                    }
                    if ((moveX - dropX) > 0) {
                        startRightByUser((moveX - dropX), 1080);
                    } else {
                        startRightByUser((moveX - dropX), -1080);
                    }
                    isTopNeedMove = false;
                } else {
                    myComponent.setTranslation((moveX - dropX) - getLeft(), 0);
                    myComponent.setAlpha(1 - (float) Math.abs((moveX - dropX)) / 540);
                }
            }
        }
    }

    private void isNeedBottomMove() {
        // 下方是否需要移动
        if (isNeedBottomMove) {
            if (cookieBottomView.isExit) {
                if (Math.abs(moveX - dropX) > 270) {
                    cookieBottomView.removeHandler();
                    if ((moveX - dropX) > 0) {
                        cookieBottomView.startRightByUser((moveX - dropX), 500);
                    } else {
                        cookieBottomView.startRightByUser((moveX - dropX), -1080);
                    }
                    isNeedBottomMove = false;
                } else {
                    cookieBottomView.myComponent.setTranslation((moveX - dropX) - getLeft(),
                            (cookieBottomView.screenY - cookieBottomView.myHeight));
                    cookieBottomView.myComponent.setAlpha(1 - (float) Math.abs((moveX - dropX)) / 540);
                }
            }
        }
    }

    /**
     * start Right By User
     *
     * @param moveFromX 从X轴的位置
     * @param moveToX   到X轴的位置
     */
    public void startRightByUser(float moveFromX, float moveToX) {
        isTopExist = false;
        isLeftExit = false;
        myComponent.setAlpha(0.5f);
        AnimatorProperty animatorProperty = myComponent.createAnimatorProperty()
                .alpha(0f)
                .moveFromX(moveFromX)
                .moveToX(moveToX)
                .setDuration(200)
                .setCurveType(Animator.CurveType.LINEAR);
        animatorProperty.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
                if (displayText != null) {
                    displayText.setText("Cookie dismissed by user");
                }
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        animatorProperty.start();
    }

    /**
     * start Restore By User
     *
     * @param moveFromX 从X轴的位置
     * @param moveToX   到X轴的位置
     * @param alpha     透明度
     */
    public void startRestoreByUser(Integer moveFromX, Integer moveToX, Float alpha) {
        myComponent.setAlpha(alpha);
        AnimatorProperty animatorProperty = myComponent.createAnimatorProperty()
                .moveFromX(moveFromX)
                .moveToX(moveToX)
                .alpha(1f)
                .setDuration(200)
                .setCurveType(Animator.CurveType.LINEAR);
        animatorProperty.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
            }

            @Override
            public void onStop(Animator animator) {
            }

            @Override
            public void onCancel(Animator animator) {
            }

            @Override
            public void onEnd(Animator animator) {
            }

            @Override
            public void onPause(Animator animator) {
            }

            @Override
            public void onResume(Animator animator) {
            }
        });
        animatorProperty.start();
    }

    /**
     * getString
     *
     * @param attrSet      attrSet
     * @param name         name
     * @param defaultValue defaultValue
     * @return String
     */
    private String getString(AttrSet attrSet, String name, String defaultValue) {
        String value = defaultValue;
        if (attrSet.getAttr(name) != null && attrSet.getAttr(name).isPresent()) {
            value = attrSet.getAttr(name).get().getStringValue();
        }
        return value;
    }
}
